﻿using System;
using System.Globalization;
using NUnit.Framework;
using SharpRomans.Exceptions;
using StoryQ;

namespace SharpRomans.Tests.NumeralSpecs
{
	[TestFixture]
	public class CreationTester
	{
		[Test]
		public void RomanNumeralCreation()
		{
			new Story("roman numerals creation")
				.InOrderTo("convert an arabic numeral to a roman numeral")
				.AsA("library user")
				.IWant("to be able to create an instance of a roman numeral from an arabic number")

				.WithScenario("negative number")
					.Given(anArabicNumeral_, -20)
					.When(theRomanNumeralIsInstantiated)
					.Then(aRangeExceptionIsThrown)

				.WithScenario("overflowing number")
					.Given(anArabicNumeral_, 4001)
					.When(theRomanNumeralIsInstantiated)
					.Then(aRangeExceptionIsThrown)

				.WithScenario("zero")
					.Given(anArabicNumeral_, 0)
					.When(theRomanNumeralIsCreated)
					.Then(isAZeroRomanNumeral)

				.WithScenario("single-figure")
					.Given(anArabicNumeral_, 50)
					.When(theRomanNumeralIsCreated)
					.Then(isARomanNumeralWithValue_WrittenAs_, 50, "L")

				.WithScenario("multiple-figures")
					.Given(anArabicNumeral_, 75)
					.When(theRomanNumeralIsCreated)
					.Then(isARomanNumeralWithValue_WrittenAs_, 75, "LXXV")

				.ExecuteWithReport();
		}

		private void isARomanNumeralWithValue_WrittenAs_(int value, string romanNumeral)
		{
			Assert.That(_subject.Value, Is.EqualTo(value));
			Assert.That(_subject.ToString(), Is.EqualTo(romanNumeral));
			Assert.That(_subject.Figures, Is.EqualTo(figuresFor(romanNumeral)));
		}

		private RomanFigure[] figuresFor(string romanNumeral)
		{
			RomanFigure[] figures = new RomanFigure[romanNumeral.Length];
			for (int i = 0; i < romanNumeral.Length; i++)
			{
				char figure = romanNumeral[i];
				figures[i] = RomanFigure.Parse(figure);
			}

			return figures;
		}


		RomanNumeral _subject;
		private void theRomanNumeralIsCreated()
		{
			_subject = new RomanNumeral(_number);
		}

		private void isAZeroRomanNumeral()
		{
			Assert.That(_subject.Value, Is.EqualTo(0));
			Assert.That(_subject.ToString(), Is.EqualTo("N"));
			Assert.That(_subject.Figures, Is.EqualTo(new[] { RomanFigure.N }));
		}

		private void aRangeExceptionIsThrown()
		{
			Assert.That(_subjectInstantion, Throws.InstanceOf<NumeralOutOfRangeException>()
				.With.Property("ActualValue").EqualTo(_number)
				.And.Message.StringContaining(RomanNumeral.MinValue.ToString())
				.And.Message.StringContaining(RomanNumeral.MaxValue.ToString()));
		}

		TestDelegate _subjectInstantion;
		private void theRomanNumeralIsInstantiated()
		{
			_subjectInstantion = () => new RomanNumeral(_number);
		}

		short _number;
		private void anArabicNumeral_(int number)
		{
			_number = (short)number;
		}
	}

	[TestFixture]
	public class BoundariesTester
	{
		[Test]
		public void RomanNumeralBoundaries()
		{
			new Story("roman numerals boundaries")
				.InOrderTo("verify whether an arabic numeral can be converted into a roman numeral")
				.AsA("library user")
				.IWant("to be able to invoke methods taking the arabic number a argument")

				.WithScenario("check a number in range")
					.Given(anArabicNumeral_, 20)
					.When(theRomanNumeralIsChecked)
					.Then(theCheckResultIs_, true)

				.WithScenario("check a negative number")
					.Given(anArabicNumeral_, -1)
					.When(theRomanNumeralIsChecked)
					.Then(theCheckResultIs_, false)

				.WithScenario("check an overflowing number")
					.Given(anArabicNumeral_, 4001)
					.When(theRomanNumeralIsChecked)
					.Then(theCheckResultIs_, false)

				.WithScenario("assert a number in range")
					.Given(anArabicNumeral_, 20)
					.When(theRomanNumeralIsAsserted)
					.Then(noExceptionIsRaised)

				.WithScenario("assert a negative number")
					.Given(anArabicNumeral_, -1)
					.When(theRomanNumeralIsAsserted)
					.Then(aRangeExceptionIsThrown)

				.WithScenario("assert an overflowing number")
					.Given(anArabicNumeral_, 4001)
					.When(theRomanNumeralIsAsserted)
					.Then(aRangeExceptionIsThrown)

				.ExecuteWithReport();
		}

		private void noExceptionIsRaised()
		{
			Assert.That(_assertion, Throws.Nothing);
		}

		private void aRangeExceptionIsThrown()
		{
			Assert.That(_assertion, Throws.InstanceOf<NumeralOutOfRangeException>()
				.With.Property("ActualValue").EqualTo(_number)
				.And.Message.StringContaining(RomanNumeral.MinValue.ToString())
				.And.Message.StringContaining(RomanNumeral.MaxValue.ToString()));
		}

		TestDelegate _assertion;
		private void theRomanNumeralIsAsserted()
		{
			_assertion = () => RomanNumeral.AssertRange(_number);
		}

		private void theCheckResultIs_(bool check)
		{
			Assert.That(_check, Is.EqualTo(check));
		}

		bool _check;
		private void theRomanNumeralIsChecked()
		{
			_check = RomanNumeral.CheckRange(_number);
		}

		short _number;
		private void anArabicNumeral_(int number)
		{
			_number = (short)number;
		}
	}

	[TestFixture]
	public class InstancesTester
	{
		[Test]
		public void RomanNumeralInstances()
		{
			new Story("roman numerals instances")
				.InOrderTo("have easy access to peculiar roman numerals")
				.AsA("library user")
				.IWant("to be able to obtain instances from the roman numeral itself")

				.WithScenario("zero")
					.Given(theZeroRomanNumeral)
					.When(itIsAccessed)
					.Then(isARomanNumeralWithValue_WrittenAs_, (short)0, "N")

				.WithScenario("min")
					.Given(theMinRomanNumeral)
					.When(itIsAccessed)
					.Then(isARomanNumeralWithValue_WrittenAs_, RomanNumeral.MinValue, "N")

				.WithScenario("max")
					.Given(theMaxRomanNumeral)
					.When(itIsAccessed)
					.Then(isARomanNumeralWithValue_WrittenAs_, RomanNumeral.MaxValue, "MMMCMXCIX")

				.ExecuteWithReport();
		}

		private void itIsAccessed() { }

		private void isARomanNumeralWithValue_WrittenAs_(short value, string romanNumeral)
		{
			Assert.That(_subject.Value, Is.EqualTo(value));
			Assert.That(_subject.ToString(), Is.EqualTo(romanNumeral));
			Assert.That(_subject.Figures, Is.EqualTo(figuresFor(romanNumeral)));
		}

		private RomanFigure[] figuresFor(string romanNumeral)
		{
			RomanFigure[] figures = new RomanFigure[romanNumeral.Length];
			for (int i = 0; i < romanNumeral.Length; i++)
			{
				char figure = romanNumeral[i];
				figures[i] = RomanFigure.Parse(figure);
			}

			return figures;
		}


		RomanNumeral _subject;
		private void theZeroRomanNumeral()
		{
			_subject = RomanNumeral.Zero;
		}

		private void theMinRomanNumeral()
		{
			_subject = RomanNumeral.Min;
		}

		private void theMaxRomanNumeral()
		{
			_subject = RomanNumeral.Max;
		}
	}

	[TestFixture]
	public class RomanNumeralComparisonTester
	{
		[Test]
		public void CompareToRomanNumeral()
		{
			new Story("compare to roman numeral")
				.InOrderTo("say that a roman numeral is greater or lower than another roman numeral")
				.AsA("library user")
				.IWant("compare a roman numeral against another roman numeral")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsComparedTo_, new RomanNumeral(1))
				.Then(IsGreaterThanZero)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsComparedTo_, new RomanNumeral(10))
				.Then(IsLessThanZero)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsComparedTo_, new RomanNumeral(10))
				.Then(IsZero)

			.WithScenario("one figure is compared to NULL")
				.Given(TheRomanNumeral_, new RomanNumeral(0))
				.When(IsComparedTo_, (RomanNumeral)null)
				.Then(IsGreaterThanZero)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanRomanNumeral()
		{
			new Story("greater than roman numeral")
				.InOrderTo("say that a numeral is greater than another numeral")
				.AsA("library user")
				.IWant("apply a greater than operator against another roman numeral")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThan_, new RomanNumeral(1))
				.Then(Is_, true)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(0))
				.When(IsGreaterThan_, new RomanNumeral(1))
				.Then(Is_, false)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsGreaterThan_, new RomanNumeral(10))
				.Then(Is_, false)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsGreaterThan_, (RomanNumeral)null)
				.Then(Is_, true)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThan_, RomanNumeral.Zero)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanOrEqualRomanNumeral()
		{
			new Story("greater than or equal to roman numeral")
				.InOrderTo("say that a numeral is greater than or equal to another numeral")
				.AsA("library user")
				.IWant("apply a greater than or equal operator against another roman numeral")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThanOrEqual_, new RomanNumeral(1))
				.Then(Is_, true)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsGreaterThanOrEqual_, new RomanNumeral(11))
				.Then(Is_, false)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(11))
				.When(IsGreaterThanOrEqual_, new RomanNumeral(11))
				.Then(Is_, true)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsGreaterThanOrEqual_, (RomanNumeral)null)
				.Then(Is_, true)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThanOrEqual_, RomanNumeral.Zero)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanRomanNumeral()
		{
			new Story("less than roman numeral")
				.InOrderTo("say that a numeral is less than another numeral")
				.AsA("library user")
				.IWant("apply a less than operator against another roman numeral")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThan_, new RomanNumeral(1))
				.Then(Is_, false)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThan_, new RomanNumeral(10))
				.Then(Is_, true)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThan_, new RomanNumeral(10))
				.Then(Is_, false)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsLessThan_, (RomanNumeral)null)
				.Then(Is_, false)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThan_, RomanNumeral.Zero)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanOrEqualToRomanNumeral()
		{
			new Story("Lless than or equal to roman numeral")
				.InOrderTo("say that a numeral is less than or equal to another numeral")
				.AsA("library user")
				.IWant("apply a less than or equal operator against another roman numeral")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThanOrEqual_, new RomanNumeral(1))
				.Then(Is_, false)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThanOrEqual_, new RomanNumeral(10))
				.Then(Is_, true)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThanOrEqual_, new RomanNumeral(10))
				.Then(Is_, true)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsLessThanOrEqual_, (RomanNumeral)null)
				.Then(Is_, false)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThanOrEqual_, RomanNumeral.Zero)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void IsZero()
		{
			Assert.That(_comparison, Is.EqualTo(0));
		}

		private void IsLessThanZero()
		{
			Assert.That(_comparison, Is.LessThan(0));
		}

		private void IsGreaterThanZero()
		{
			Assert.That(_comparison, Is.GreaterThan(0));
		}

		private int _comparison;

		private void IsComparedTo_(RomanNumeral anotherFigure)
		{
			_comparison = _subject.CompareTo(anotherFigure);
		}

		RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private void IsGreaterThan_(RomanNumeral right)
		{
			operate(left => left > right);
		}

		private void IsLessThan_(RomanNumeral right)
		{
			operate(left => left < right);
		}

		private void IsGreaterThanOrEqual_(RomanNumeral right)
		{
			operate(left => left >= right);
		}

		private void IsLessThanOrEqual_(RomanNumeral right)
		{
			operate(left => left <= right);
		}

		bool _operation;
		private void operate(Func<RomanNumeral, bool> operation)
		{
			_operation = operation(_subject);
		}

		private void Is_(bool value)
		{
			Assert.That(_operation, Is.EqualTo(value));
		}
	}

	[TestFixture]
	public class RomanFigureComparisonTester
	{
		[Test]
		public void CompareToRomanFigure()
		{
			new Story("compare to roman figure")
				.InOrderTo("say that a roman numeral is greater or lower than a roman figure")
				.AsA("library user")
				.IWant("compare a roman numeral against a roman figure")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsComparedTo_, RomanFigure.I)
				.Then(IsGreaterThanZero)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsComparedTo_, RomanFigure.X)
				.Then(IsLessThanZero)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsComparedTo_, RomanFigure.X)
				.Then(IsZero)

			.WithScenario("one figure is compared to NULL")
				.Given(TheRomanNumeral_, new RomanNumeral(0))
				.When(IsComparedTo_, (RomanFigure)null)
				.Then(IsGreaterThanZero)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanRomanFigure()
		{
			new Story("greater than roman figure")
				.InOrderTo("say that a numeral is greater than a figure")
				.AsA("library user")
				.IWant("apply a greater than operator against a roman figure")

			.WithScenario("one numeral is greater than a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThan_, RomanFigure.I)
				.Then(Is_, true)

			.WithScenario("one numeral is less than a figure")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsGreaterThan_, RomanFigure.I)
				.Then(Is_, false)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsGreaterThan_, RomanFigure.X)
				.Then(Is_, false)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsGreaterThan_, (RomanFigure)null)
				.Then(Is_, true)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThan_, RomanFigure.N)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanOrEqualRomanFigure()
		{
			new Story("greater than or equal to roman figure")
				.InOrderTo("say that a numeral is greater than or equal to a figure")
				.AsA("library user")
				.IWant("apply a greater than or equal operator against a roman figure")

			.WithScenario("one numeral is greater than a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThanOrEqual_, RomanFigure.I)
				.Then(Is_, true)

			.WithScenario("one numeral is less than a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsGreaterThanOrEqual_, RomanFigure.D)
				.Then(Is_, false)

			.WithScenario("one numeral is equal to a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(50))
				.When(IsGreaterThanOrEqual_, RomanFigure.L)
				.Then(Is_, true)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsGreaterThanOrEqual_, (RomanFigure)null)
				.Then(Is_, true)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThanOrEqual_, RomanFigure.N)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanRomanFigure()
		{
			new Story("less than roman figure")
				.InOrderTo("say that a numeral is less than a figure")
				.AsA("library user")
				.IWant("apply a less than operator against a roman figure")

			.WithScenario("one numeral is greater than a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThan_, RomanFigure.I)
				.Then(Is_, false)

			.WithScenario("one numeral is less than a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThan_, RomanFigure.X)
				.Then(Is_, true)

			.WithScenario("one numeral is equal to a figure")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThan_, RomanFigure.X)
				.Then(Is_, false)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsLessThan_, (RomanFigure)null)
				.Then(Is_, false)

				.WithScenario("NULL is compared to a figure")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThan_, RomanFigure.N)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanOrEqualToRomanFigure()
		{
			new Story("Lless than or equal to roman figure")
				.InOrderTo("say that a numeral is less than or equal to a figure")
				.AsA("library user")
				.IWant("apply a less than or equal operator against a roman figure")

			.WithScenario("one numeral is greater than another")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThanOrEqual_, RomanFigure.I)
				.Then(Is_, false)

			.WithScenario("one numeral is less than another")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThanOrEqual_, RomanFigure.X)
				.Then(Is_, true)

			.WithScenario("one numeral is equal to another")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThanOrEqual_, RomanFigure.X)
				.Then(Is_, true)

			.WithScenario("one numeral is compared to NULL")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(IsLessThanOrEqual_, (RomanFigure)null)
				.Then(Is_, false)

				.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThanOrEqual_, RomanFigure.N)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void IsZero()
		{
			Assert.That(_comparison, Is.EqualTo(0));
		}

		private void IsLessThanZero()
		{
			Assert.That(_comparison, Is.LessThan(0));
		}

		private void IsGreaterThanZero()
		{
			Assert.That(_comparison, Is.GreaterThan(0));
		}

		private int _comparison;

		private void IsComparedTo_(RomanFigure figure)
		{
			_comparison = _subject.CompareTo(figure);
		}

		RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private void IsGreaterThan_(RomanFigure right)
		{
			operate(left => left > right);
		}

		private void IsLessThan_(RomanFigure right)
		{
			operate(left => left < right);
		}

		private void IsGreaterThanOrEqual_(RomanFigure right)
		{
			operate(left => left >= right);
		}

		private void IsLessThanOrEqual_(RomanFigure right)
		{
			operate(left => left <= right);
		}

		bool _operation;
		private void operate(Func<RomanNumeral, bool> operation)
		{
			_operation = operation(_subject);
		}

		private void Is_(bool value)
		{
			Assert.That(_operation, Is.EqualTo(value));
		}
	}

	[TestFixture]
	public class NumberComparisonTester
	{
		[Test]
		public void CompareToNumber()
		{
			new Story("compare to number")
				.InOrderTo("say that a numeral is greater or lower than a number")
				.AsA("library user")
				.IWant("compare a roman numeral against a number")

			.WithScenario("one numeral is greater than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsComparedTo_, 1)
				.Then(IsGreaterThanZero)

			.WithScenario("one numeral is less than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsComparedTo_, 10)
				.Then(IsLessThanZero)

			.WithScenario("one numeral is equal to a number")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsComparedTo_, 10)
				.Then(IsZero)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanNumber()
		{
			new Story("greater than number")
				.InOrderTo("say that a numeral is greater than a number")
				.AsA("library user")
				.IWant("apply a greater than operator against a  number")

			.WithScenario("one numeral is greater than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThan_, 1)
				.Then(Is_, true)

			.WithScenario("one numeral is less than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsGreaterThan_, 10)
				.Then(Is_, false)

			.WithScenario("one numeral is equal to a number")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsGreaterThan_, 10)
				.Then(Is_, false)

			.WithScenario("NULL is compared to a number")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThan_, 0)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void GreaterThanOrEqualToNumber()
		{
			new Story("greater than or equal to number")
				.InOrderTo("say that a numeral is greater than or equal to a number")
				.AsA("library user")
				.IWant("apply a greater than or equal operator against a number")

			.WithScenario("one numeral is greater than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsGreaterThanOrEqual_, 1)
				.Then(Is_, true)

			.WithScenario("one numeral is less than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsGreaterThanOrEqual_, 10)
				.Then(Is_, false)

			.WithScenario("one numeral is equal to a number")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsGreaterThanOrEqual_, 10)
				.Then(Is_, true)

			.WithScenario("NULL is compared to a a number")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsGreaterThanOrEqual_, 0)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanNumber()
		{
			new Story("less than number")
				.InOrderTo("say that a numeral is less than a number")
				.AsA("library user")
				.IWant("apply a less than operator against a number")

			.WithScenario("one numeral is greater than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThan_, 1)
				.Then(Is_, false)

			.WithScenario("one numeral is less than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThan_, 10)
				.Then(Is_, true)

			.WithScenario("one numeral is equal to a number")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThan_, 10)
				.Then(Is_, false)

			.WithScenario("NULL is compared to a number")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThan_, 0)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		[Test]
		public void LessThanOrEqualToNumber()
		{
			new Story("less than or equal to Number")
				.InOrderTo("say that a numeral is less than or equal to a number")
				.AsA("library user")
				.IWant("apply a less than or equal operator against a number")

			.WithScenario("one numeral is greater than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(IsLessThanOrEqual_, 1)
				.Then(Is_, false)

			.WithScenario("one numeral is less than a number")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(IsLessThanOrEqual_, 10)
				.Then(Is_, true)

			.WithScenario("one numeral is equal to a number")
				.Given(TheRomanNumeral_, new RomanNumeral(10))
				.When(IsLessThanOrEqual_, 10)
				.Then(Is_, true)

			.WithScenario("NULL is compared to a numeral")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(IsLessThanOrEqual_, 0)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void IsZero()
		{
			Assert.That(_comparison, Is.EqualTo(0));
		}

		private void IsLessThanZero()
		{
			Assert.That(_comparison, Is.LessThan(0));
		}

		private void IsGreaterThanZero()
		{
			Assert.That(_comparison, Is.GreaterThan(0));
		}

		private int _comparison;

		private void IsComparedTo_(int number)
		{
			_comparison = _subject.CompareTo((short)number);
		}

		RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private void IsGreaterThan_(int right)
		{
			operate(left => left > (short)right);
		}

		private void IsLessThan_(int right)
		{
			operate(left => left < (short)right);
		}

		private void IsGreaterThanOrEqual_(int right)
		{
			operate(left => left >= (short)right);
		}

		private void IsLessThanOrEqual_(int right)
		{
			operate(left => left <= (short)right);
		}

		bool _operation;
		private void operate(Func<RomanNumeral, bool> operation)
		{
			_operation = operation(_subject);
		}

		private void Is_(bool value)
		{
			Assert.That(_operation, Is.EqualTo(value));
		}
	}

	[TestFixture]
	public class EquatableTester
	{
		[Test]
		public void Equatable()
		{
			new Story("non generic equatable")
				.InOrderTo("say that an object is equal to a roman numeral")
				.AsA("library user")
				.IWant("to use .Equals() against an object")

			.WithScenario("a roman numeral is compared against a boxed short with the same value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)((short)5))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against a boxed short with a different value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)((short)10))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against the same objectified numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against another objectified numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)new RomanNumeral(10))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against the same objectified figure")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)RomanFigure.V)
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against another objectified figure")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)RomanFigure.C)
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)null)
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against a boxed int with the same value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (object)5)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private bool _operation;
		private void ComparedTo_(object o)
		{
			_operation = _subject.Equals(o);
		}

		private RomanNumeral _subject;

		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}
	}

	[TestFixture]
	public class EquatableToRomanNumeralTester
	{
		[Test]
		public void EquatableToRomanNumeral()
		{
			new Story("equatable to roman numeral")
				.InOrderTo("say that a numeral is equal to another numeral")
				.AsA("library user")
				.IWant("to use IEquatable<RomanNumeral> methods against a roman numeral")

			.WithScenario("a roman numeral is compared against the same roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against not the same roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, new RomanNumeral(15))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (RomanNumeral)null)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private bool _operation;

		private void ComparedTo_(RomanNumeral anotherNumeral)
		{
			_operation = _subject.Equals(anotherNumeral);
		}

		private IEquatable<RomanNumeral> _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}
	}

	[TestFixture]
	public class EquatableToShortFigureTester
	{
		[Test]
		public void EquatableToShort()
		{
			new Story("equatable to a number")
				.InOrderTo("say that a numeral is equal to a number")
				.AsA("library user")
				.IWant("to use IEquatable<short> methods against a roman numeral")

			.WithScenario("a roman numeral is compared against a number with the same value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, 5)
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against a number with a different value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, 10)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private bool _operation;
		private void ComparedTo_(int number)
		{
			_operation = _subject.Equals((short)number);
		}

		private IEquatable<short> _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}
	}

	[TestFixture]
	public class EquatableToRomanFigureTester
	{
		[Test]
		public void EquatableToRomanFigure()
		{
			new Story("equatable to roman figure")
				.InOrderTo("say that a numeral is equal to a figure")
				.AsA("library user")
				.IWant("to use IEquatable<RomanNumeral> methods against a roman numeral")

			.WithScenario("a roman numeral is compared against the same roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against not the same roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, new RomanNumeral(15))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(ComparedTo_, (RomanNumeral)null)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private bool _operation;

		private void ComparedTo_(RomanNumeral anotherNumeral)
		{
			_operation = _subject.Equals(anotherNumeral);
		}

		private IEquatable<RomanNumeral> _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}
	}

	[TestFixture]
	public class RomanNumeralEqualityOperatorTester
	{
		[Test]
		public void EqualsToRomanNumeral()
		{
			new Story("equality to roman numeral")
				.InOrderTo("say that a numeral is equal to another numeral")
				.AsA("library user")
				.IWant("to use the equality operator against a roman numeral")

			.WithScenario("a roman numeral is compared against the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(EqualTo_, new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against not the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(EqualTo_, new RomanNumeral(15))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanFigure_, RomanNumeral.Zero)
				.When(EqualTo_, (RomanNumeral)null)
				.Then(Is_, false)

			.WithScenario("null is compared against a roman numeral")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(EqualTo_, RomanNumeral.Zero)
				.Then(Is_, false)

			.WithScenario("null is compared against null")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(EqualTo_, (RomanNumeral)null)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanFigure_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private bool _operation;
		private void EqualTo_(RomanNumeral anotherNumeral)
		{
			_operation = _subject == anotherNumeral;
		}
	}

	[TestFixture]
	public class RomanNumeralInequalityOperatorTester
	{
		[Test]
		public void NotEqualToRomanNumeral()
		{
			new Story("inequality to roman numeral")
				.InOrderTo("say that a numeral is not equal to another numeral")
				.AsA("library user")
				.IWant("to use the inequality operator against a roman numeral")

			.WithScenario("a roman numeral is compared against the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, new RomanNumeral(5))
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against not the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, new RomanNumeral(15))
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, (RomanNumeral)null)
				.Then(Is_, true)

			.WithScenario("null is compared against a roman numeral")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(NotEqualTo_, new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("null is compared against null")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(NotEqualTo_, (RomanNumeral)null)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private bool _operation;
		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanFigure_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private void NotEqualTo_(RomanNumeral anotherNumeral)
		{
			_operation = _subject != anotherNumeral;
		}
	}

	[TestFixture]
	public class ShortEqualityOperatorTester
	{
		[Test]
		public void EqualsToShort()
		{
			new Story("number equality")
				.InOrderTo("say that a numeral is equal to a short numeral")
				.AsA("library user")
				.IWant("to use the equality operator against a short numeral")

			.WithScenario("a roman numeral is compared against a short value equal to the roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(EqualTo_, 5)
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against a short value not equal to the roman numeral")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(EqualTo_, 10)
				.Then(Is_, false)

			.WithScenario("null is compared against short value")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(EqualTo_, 10)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private bool _operation;
		private void EqualTo_(int value)
		{
			_operation = _subject == (short)value;
		}
	}

	[TestFixture]
	public class ShortInequalityOperatorTester
	{
		[Test]
		public void NotEqualToShort()
		{
			new Story("inequality to number")
				.InOrderTo("say that a numeral is not equal to a short numeral")
				.AsA("library user")
				.IWant("to use the inequality operator against a short numeral")

			.WithScenario("a roman numeral is compared against a short numeral with the same value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(NotEqualTo_, 5)
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against a short numeral not the same value")
				.Given(TheRomanNumeral_, new RomanNumeral(5))
				.When(NotEqualTo_, 10)
				.Then(Is_, true)

			.WithScenario("null is compared against a short value")
				.Given(TheRomanNumeral_, (RomanNumeral)null)
				.When(NotEqualTo_, 10)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private bool _operation;

		private void NotEqualTo_(int value)
		{
			_operation = _subject != (short)value;
		}
	}

	[TestFixture]
	public class InverseShortEqualityOperatorTester
	{
		[Test]
		public void EqualsToShort()
		{
			new Story("equality to number")
				.InOrderTo("say that a short numeral is equal to the value of a roman numeral")
				.AsA("library user")
				.IWant("to use the equality operator against a roman numeral")

			.WithScenario("a short numeral is compared against the same value of a roman numeral")
				.Given(TheNumber_, 5)
				.When(EqualTo_, new RomanNumeral(5))
				.Then(Is_, true)

			.WithScenario("a short numeral is compared against not the same value of a roman numeral")
				.Given(TheNumber_, 5)
				.When(EqualTo_, new RomanNumeral(15))
				.Then(Is_, false)

			.WithScenario("a short numeral is compared against null")
				.Given(TheNumber_, 0)
				.When(EqualTo_, (RomanNumeral)null)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private short _subject;
		private void TheNumber_(int value)
		{
			_subject = (short)value;
		}

		private bool _operation;
		private void EqualTo_(RomanNumeral numeral)
		{
			_operation = _subject == numeral;
		}
	}

	[TestFixture]
	public class InverseShortInequalityOperatorTester
	{
		[Test]
		public void NotEqualToShort()
		{
			new Story("Inequality to number")
				.InOrderTo("say that a number is not equal to a roman numeral")
				.AsA("library user")
				.IWant("to use the inequality operator against a roman numeral")

			.WithScenario("a short numeral is compared against the same value of a roman numeral")
				.Given(TheNumber_, 5)
				.When(NotEqualTo_, new RomanNumeral(5))
				.Then(Is_, false)

			.WithScenario("a short numeral is compared against not the same value of a roman numeral")
				.Given(TheNumber_, 5)
				.When(NotEqualTo_, new RomanNumeral(12))
				.Then(Is_, true)

			.WithScenario("a short numeral is compared against null")
				.Given(TheNumber_, 5)
				.When(NotEqualTo_, (RomanNumeral)null)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private short _subject;
		private void TheNumber_(int value)
		{
			_subject = (short)value;
		}

		private bool _operation;
		private void NotEqualTo_(RomanNumeral numeral)
		{
			_operation = _subject != numeral;
		}
	}

	[TestFixture]
	public class RomanFigureEqualityOperatorTester
	{
		[Test]
		public void EqualsToRomanFigure()
		{
			new Story("equality to roman figure")
				.InOrderTo("say that a numeral is equal to a figure")
				.AsA("library user")
				.IWant("to use the equality operator against a roman figure")

			.WithScenario("a roman numeral is compared against the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(EqualTo_, RomanFigure.V)
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against not the same roman numeral")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(EqualTo_, RomanFigure.D)
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanFigure_, RomanNumeral.Zero)
				.When(EqualTo_, (RomanFigure)null)
				.Then(Is_, false)

			.WithScenario("null is compared against a roman numeral")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(EqualTo_, RomanFigure.N)
				.Then(Is_, false)

			.WithScenario("null is compared against null")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(EqualTo_, (RomanFigure)null)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanFigure_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private bool _operation;
		private void EqualTo_(RomanFigure figure)
		{
			_operation = _subject == figure;
		}
	}

	[TestFixture]
	public class RomanFigureInequalityOperatorTester
	{
		[Test]
		public void NotEqualToRomanFigure()
		{
			new Story("inequality to roman figure")
				.InOrderTo("say that a numeral is not equal to a roman figure")
				.AsA("library user")
				.IWant("to use the inequality operator against a roman figure")

			.WithScenario("a roman numeral is compared against the same roman figure")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, RomanFigure.V)
				.Then(Is_, false)

			.WithScenario("a roman numeral is compared against not the same roman figure")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, RomanFigure.L)
				.Then(Is_, true)

			.WithScenario("a roman numeral is compared against null")
				.Given(TheRomanFigure_, new RomanNumeral(5))
				.When(NotEqualTo_, (RomanFigure)null)
				.Then(Is_, true)

			.WithScenario("null is compared against a roman figure")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(NotEqualTo_, RomanFigure.N)
				.Then(Is_, true)

			.WithScenario("null is compared against null")
				.Given(TheRomanFigure_, (RomanNumeral)null)
				.When(NotEqualTo_, (RomanFigure)null)
				.Then(Is_, false)

			.ExecuteWithReport();
		}

		private bool _operation;
		private void Is_(bool result)
		{
			Assert.That(_operation, Is.EqualTo(result));
		}

		private RomanNumeral _subject;
		private void TheRomanFigure_(RomanNumeral numeral)
		{
			_subject = numeral;
		}

		private void NotEqualTo_(RomanFigure figure)
		{
			_operation = _subject != figure;
		}
	}

	[TestFixture]
	public class ConvertibleTester
	{
		[Test]
		public void ConvertToBoolean()
		{
			new Story("convert to Boolean")
				.InOrderTo("convert a roman numeral to boolean whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToBoolean)
				.Then(Is_, false)

			.WithScenario("one")
				.Given(TheRomanNumeral_, new RomanNumeral(1))
				.When(ConvertedToBoolean)
				.Then(Is_, true)

			.WithScenario("more than one")
				.Given(TheRomanNumeral_, new RomanNumeral(51))
				.When(ConvertedToBoolean)
				.Then(Is_, true)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToBoolean)
				.Then(Is_, true)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToChar()
		{
			new Story("convert to Char")
				.InOrderTo("convert a roman numeral to a char whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToChar)
				.Then(Is_, 'N')

			.WithScenario("single figure")
				.Given(TheRomanNumeral_, new RomanNumeral(500))
				.When(ConvertedToChar)
				.Then(Is_, 'D')

			.WithScenario("multiple figure")
				.Given(TheRomanNumeral_, new RomanNumeral(11))
				.When(ConvertedToChar)
				.Then(ThrowsException)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToSByte()
		{
			new Story("convert to SByte")
				.InOrderTo("convert a roman numeral to a signed byte whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToSByte)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(101))
				.When(ConvertedToSByte)
				.Then(Is_, 101)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToSByte)
				.Then(Overflows)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToByte()
		{
			new Story("convert to Byte")
				.InOrderTo("convert a roman numeral to a byte whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToByte)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToByte)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToByte)
				.Then(Overflows)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToShort()
		{
			new Story("convert to short")
				.InOrderTo("convert a roman numeral to a short whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToShort)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToShort)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToShort)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToUShort()
		{
			new Story("convert to UShort")
				.InOrderTo("convert a roman numeral to an unsigned short whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToUShort)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToUShort)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToUShort)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToInt()
		{
			new Story("convert to Int")
				.InOrderTo("convert a roman numeral to an int whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToInt)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToInt)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToInt)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToUInt()
		{
			new Story("convert to UInt")
				.InOrderTo("convert a roman numeral to an unsigned int whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToUInt)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToUInt)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToUInt)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToLong()
		{
			new Story("convert to Long")
				.InOrderTo("convert a roman numeral to a long whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToLong)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToLong)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToLong)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToULong()
		{
			new Story("convert to ULong")
				.InOrderTo("convert a roman numeral to an unsigned long whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToULong)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToULong)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToULong)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToFloat()
		{
			new Story("convert to Float")
				.InOrderTo("convert a roman numeral to a float whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToFloat)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToFloat)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToFloat)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToDouble()
		{
			new Story("convert to Double")
				.InOrderTo("convert a roman numeral to a double whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToDouble)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToDouble)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToDouble)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToDecimal()
		{
			new Story("convert to Decimal")
				.InOrderTo("convert a roman numeral to a decimal whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToDecimal)
				.Then(Is_, 0)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToDecimal)
				.Then(Is_, 100)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToDecimal)
				.Then(Is_, 3999)

			.ExecuteWithReport();
		}

		[Test]
		public void ConvertToDateTime()
		{
			new Story("convert to DateTime")
				.InOrderTo("convert a roman numeral to date-time whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("zero")
				.Given(TheRomanNumeral_, RomanNumeral.Zero)
				.When(ConvertedToDateTime)
				.Then(CannotCast)

			.WithScenario("less than max")
				.Given(TheRomanNumeral_, new RomanNumeral(100))
				.When(ConvertedToDateTime)
				.Then(CannotCast)

			.WithScenario("max")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedToDateTime)
				.Then(CannotCast)

			.ExecuteWithReport();
		}

		[Test]
		public void ChangeType()
		{
			new Story("change type")
				.InOrderTo("convert a roman numeral to a clr type whenever possible")
				.AsA("library user")
				.IWant("Convert() to a roman numeral")

			.WithScenario("supported type")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedTo_, typeof(long))
				.Then(Is_, 3999)

			.WithScenario("overflowing type")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedTo_, typeof(byte))
				.Then(Overflows)

			.WithScenario("unsupported type")
				.Given(TheRomanNumeral_, RomanNumeral.Min)
				.When(ConvertedTo_, typeof(TimeSpan))
				.Then(CannotCast)

			.WithScenario("unsupported type")
				.Given(TheRomanNumeral_, RomanNumeral.Min)
				.When(ConvertedTo_, typeof(Exception))
				.Then(CannotCast)

			.WithScenario("itself")
				.Given(TheRomanNumeral_, RomanNumeral.Max)
				.When(ConvertedTo_, typeof(RomanNumeral))
				.Then(Is_, RomanNumeral.Max)

			.ExecuteWithReport();
		}

		Func<object> _conversion;
		private void ConvertedToBoolean()
		{
			_conversion = () => Convert.ToBoolean(_subject);
		}

		private void ConvertedToChar()
		{
			_conversion = () => Convert.ToChar(_subject);
		}

		private void ConvertedToSByte()
		{
			_conversion = () => Convert.ToSByte(_subject);
		}

		private void ConvertedToByte()
		{
			_conversion = () => Convert.ToByte(_subject);
		}

		private void ConvertedToShort()
		{
			_conversion = () => Convert.ToInt16(_subject);
		}

		private void ConvertedToUShort()
		{
			_conversion = () => Convert.ToUInt16(_subject);
		}

		private void ConvertedToInt()
		{
			_conversion = () => Convert.ToInt32(_subject);
		}

		private void ConvertedToUInt()
		{
			_conversion = () => Convert.ToUInt32(_subject);
		}

		private void ConvertedToLong()
		{
			_conversion = () => Convert.ToInt64(_subject);
		}

		private void ConvertedToULong()
		{
			_conversion = () => Convert.ToUInt64(_subject);
		}

		private void ConvertedToFloat()
		{
			_conversion = () => Convert.ToSingle(_subject);
		}

		private void ConvertedToDouble()
		{
			_conversion = () => Convert.ToDouble(_subject);
		}

		private void ConvertedToDecimal()
		{
			_conversion = () => Convert.ToDecimal(_subject);
		}

		private void ConvertedToDateTime()
		{
			_conversion = () => Convert.ToDateTime(_subject);
		}

		private void ConvertedTo_(Type to)
		{
			_conversion = () => Convert.ChangeType(_subject, to);
		}

		RomanNumeral _subject;
		private void TheRomanNumeral_(RomanNumeral subject)
		{
			_subject = subject;
		}

		private void Is_(bool value)
		{
			Assert.That(_conversion(), Is.EqualTo(value));
		}

		private void Is_(char value)
		{
			Assert.That(_conversion(), Is.EqualTo(value));
		}

		private void ThrowsException()
		{
			TestDelegate conversion = () => _conversion();
			Assert.That(conversion, Throws.InstanceOf<FormatException>());
		}

		private void Is_(int value)
		{
			Assert.That(_conversion(), Is.EqualTo(value));
		}

		private void Is_(RomanNumeral value)
		{
			Assert.That(_conversion(), Is.EqualTo(value));
		}

		private void Overflows()
		{
			TestDelegate conversion = () => _conversion();
			Assert.That(conversion, Throws.InstanceOf<OverflowException>());
		}

		private void CannotCast()
		{
			TestDelegate conversion = () => _conversion();
			Assert.That(conversion, Throws.InstanceOf<InvalidCastException>()
				.With.Message.StringContaining(typeof(RomanFigure).Name));
		}
	}

	[TestFixture]
	public class RomanNumeralAdditionTester
	{
		[Test]
		public void RomanNumeralAddition()
		{
			new Story("arithmetic addition")
				.InOrderTo("calculate the value of adding one roman numeral to another roman numeral")
				.AsA("library user")
				.IWant("to use an instance method on a roman numeral")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(plus_, new RomanNumeral(11))
					.Then(theResultIs_, new RomanNumeral(31))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Max)
					.When(plus_, new RomanNumeral(1))
					.Then(theResultOverflows)

				.WithScenario("adding NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(plus_, (RomanNumeral)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.ExecuteWithReport();
		}

		[Test]
		public void RomanNumeralAdditionOperation()
		{
			new Story("arithmetic addition")
				.InOrderTo("calculate the value of adding one roman numeral to another roman numeral")
				.AsA("library user")
				.IWant("to use an operator")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(added_, new RomanNumeral(11))
					.Then(theResultIs_, new RomanNumeral(31))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Max)
					.When(added_, new RomanNumeral(1))
					.Then(theResultOverflows)

				.WithScenario("adding NULL to not NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(added_, (RomanNumeral)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.WithScenario("adding not NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(added_, new RomanNumeral(13))
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _operand))

				.WithScenario("adding NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(added_, (RomanNumeral)null)
					.Then(theResultIs_, (RomanNumeral)null)

				.ExecuteWithReport();
		}

		private void isNotDestructive()
		{
			Assert.That(_subject, Is.Not.SameAs(_result).And.Not.EqualTo(_result));
			Assert.That(_operand, Is.Not.SameAs(_result).And.Not.EqualTo(_result));
		}

		private void theResultIsTheSameAs_(Func<RomanNumeral> same)
		{
			Assert.That(_addition(), Is.SameAs(same()));
		}

		private void theResultOverflows()
		{
			TestDelegate operation = () => _addition();
			Assert.That(operation, Throws.InstanceOf<NumeralOutOfRangeException>()
				.And.Message.StringContaining(RomanNumeral.MinValue.ToString())
				.And.Message.StringContaining(RomanNumeral.MaxValue.ToString()));
		}

		private RomanNumeral _result;
		private void theResultIs_(RomanNumeral result)
		{
			_result = result;
			Assert.That(_addition(), Is.EqualTo(result));
		}

		private Func<RomanNumeral> _addition;
		private RomanNumeral _operand;
		private void plus_(RomanNumeral operand)
		{
			_operand = operand;
			_addition = () => _subject.Plus(operand);
		}
		private void added_(RomanNumeral operand)
		{
			_operand = operand;
			_addition = () => _subject + operand;
		}

		RomanNumeral _subject;
		private void theRomanNumeral_(RomanNumeral subject)
		{
			_subject = subject;
		}
	}

	[TestFixture]
	public class RomanFigureAdditionTester
	{
		[Test]
		public void RomanFigureAddition()
		{
			new Story("arithmetic addition")
				.InOrderTo("calculate the value of adding a roman figure to a roman numeral")
				.AsA("library user")
				.IWant("to use an instance method on a roman numeral")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(plus_, RomanFigure.V)
					.Then(theResultIs_, new RomanNumeral(25))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Max)
					.When(plus_, RomanFigure.I)
					.Then(theResultOverflows)

				.WithScenario("adding NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(plus_, (RomanFigure)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.ExecuteWithReport();
		}

		[Test]
		public void RomanFigureAdditionOperation()
		{
			new Story("arithmetic addition")
				.InOrderTo("calculate the value of adding a roman figure to a roman numeral")
				.AsA("library user")
				.IWant("to use an operator")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(added_, RomanFigure.V)
					.Then(theResultIs_, new RomanNumeral(25))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Max)
					.When(added_, RomanFigure.I)
					.Then(theResultOverflows)

				.WithScenario("adding NULL to not NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(added_, (RomanFigure)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.WithScenario("adding not NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(added_, RomanFigure.V)
					.Then(theResultIs_, new RomanNumeral(5))

				.WithScenario("adding NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(added_, (RomanFigure)null)
					.Then(theResultIs_, (RomanNumeral)null)

				.ExecuteWithReport();
		}

		private void isNotDestructive()
		{
			Assert.That(_subject, Is.Not.SameAs(_result).And.Not.EqualTo(_result));
		}

		private void theResultIsTheSameAs_(Func<RomanNumeral> same)
		{
			Assert.That(_addition(), Is.SameAs(same()));
		}

		private void theResultOverflows()
		{
			TestDelegate operation = () => _addition();
			Assert.That(operation, Throws.InstanceOf<NumeralOutOfRangeException>()
				.And.Message.StringContaining(RomanNumeral.MinValue.ToString())
				.And.Message.StringContaining(RomanNumeral.MaxValue.ToString()));
		}

		private RomanNumeral _result;
		private void theResultIs_(RomanNumeral result)
		{
			_result = result;
			Assert.That(_addition(), Is.EqualTo(result));
		}

		private Func<RomanNumeral> _addition;
		private RomanFigure _operand;
		private void plus_(RomanFigure operand)
		{
			_operand = operand;
			_addition = () => _subject.Plus(operand);
		}
		private void added_(RomanFigure operand)
		{
			_operand = operand;
			_addition = () => _subject + operand;
		}

		RomanNumeral _subject;
		private void theRomanNumeral_(RomanNumeral subject)
		{
			_subject = subject;
		}
	}

	[TestFixture]
	public class RomanNumeralSubstractionTester
	{
		[Test]
		public void RomanNumeralSubstraction()
		{
			new Story("arithmetic substraction")
				.InOrderTo("calculate the value of substracting one roman numeral from another roman numeral")
				.AsA("library user")
				.IWant("to use an instance method on a roman numeral")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(minus_, new RomanNumeral(11))
					.Then(theResultIs_, new RomanNumeral(9))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Min)
					.When(minus_, new RomanNumeral(1))
					.Then(theResultOverflows)

				.WithScenario("substracting NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(minus_, (RomanNumeral)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.ExecuteWithReport();
		}

		[Test]
		public void RomanNumeralSubstractionOperation()
		{
			new Story("arithmetic substraction")
				.InOrderTo("calculate the value of substracting one roman numeral from another roman numeral")
				.AsA("library user")
				.IWant("to use an operator")

				.WithScenario("bounded operation")
					.Given(theRomanNumeral_, new RomanNumeral(20))
					.When(substracted_, new RomanNumeral(11))
					.Then(theResultIs_, new RomanNumeral(9))
					.And(isNotDestructive)

				.WithScenario("overflowing operation")
					.Given(theRomanNumeral_, RomanNumeral.Min)
					.When(substracted_, new RomanNumeral(1))
					.Then(theResultOverflows)

				.WithScenario("substracting NULL to not NULL")
					.Given(theRomanNumeral_, new RomanNumeral(13))
					.When(substracted_, (RomanNumeral)null)
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _subject))

				.WithScenario("substracting not NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(substracted_, new RomanNumeral(13))
					.Then(theResultIsTheSameAs_, new Func<RomanNumeral>(() => _operand))

				.WithScenario("substracting NULL to NULL")
					.Given(theRomanNumeral_, (RomanNumeral)null)
					.When(substracted_, (RomanNumeral)null)
					.Then(theResultIs_, (RomanNumeral)null)

				.ExecuteWithReport();
		}

		private void isNotDestructive()
		{
			Assert.That(_subject, Is.Not.SameAs(_result).And.Not.EqualTo(_result));
			Assert.That(_operand, Is.Not.SameAs(_result).And.Not.EqualTo(_result));
		}

		private void theResultIsTheSameAs_(Func<RomanNumeral> same)
		{
			Assert.That(_substraction(), Is.SameAs(same()));
		}

		private void theResultOverflows()
		{
			TestDelegate operation = () => _substraction();
			Assert.That(operation, Throws.InstanceOf<NumeralOutOfRangeException>()
				.And.Message.StringContaining(RomanNumeral.MinValue.ToString())
				.And.Message.StringContaining(RomanNumeral.MaxValue.ToString()));
		}

		private RomanNumeral _result;
		private void theResultIs_(RomanNumeral result)
		{
			_result = result;
			Assert.That(_substraction(), Is.EqualTo(result));
		}

		private Func<RomanNumeral> _substraction;
		private RomanNumeral _operand;
		private void minus_(RomanNumeral operand)
		{
			_operand = operand;
			_substraction = () => _subject.Minus(operand);
		}
		private void substracted_(RomanNumeral operand)
		{
			_operand = operand;
			_substraction = () => _subject - operand;
		}

		RomanNumeral _subject;
		private void theRomanNumeral_(RomanNumeral subject)
		{
			_subject = subject;
		}
	}

	[TestFixture]
	public class ParseTester
	{
		// only meaningful "integration tests". Not there yet
	}
}
